<?php
declare (strict_types=1);

namespace app\api\version\v1;

use app\api\exception\HttpExceptionHandle;
use app\api\validate\LoginValidate;
use app\api\validate\PasswordValidate;
use app\common\auth\JwtAuth;
use app\common\controller\Api;

use app\common\lib\HttpError;
use app\common\model\Member;
use ErrorException;
use Exception;
use think\exception\ValidateException;
use think\facade\Db;
use think\facade\Env;
use think\facade\Log;
use think\response\Json;


/**
 * | Notes：登录
 * +----------------------------------------------------------------------
 * | PHP Version 7.2+
 * +----------------------------------------------------------------------
 * | Copyright (c) 2011-2020 https://www.xxq.com.cn, All rights reserved.
 * +----------------------------------------------------------------------
 * | Author: 和好 <389123492@qq.com>
 * +----------------------------------------------------------------------
 * | Date: 2020/11/3 18:05
 * +----------------------------------------------------------------------
 */
class Login extends Api
{

    public function initialize()
    {
        parent::initialize(); // TODO: Change the autogenerated stub
    }


    /**
     * @OA\Post(path="/v1/authLogin",
     *   tags={"登录管理"},
     *   summary="登录",
     *   @OA\Parameter(name="token", in="header", description="token", @OA\Schema(type="string", default="123456")),
     *     @OA\RequestBody(
     *     @OA\MediaType(
     *       mediaType="multipart/form-data",
     *         @OA\Schema(
     *           @OA\Property(description="手机号/邮箱", property="username", type="string", default="15210999641"),
     *           @OA\Property(description="密码", property="password", type="string", default="123456"),
     *           @OA\Property(description="验证码", property="verify_code", type="string", default="1234"),
     *           @OA\Property(description="登录类型 1验证码 2密码", property="loing_type", type="int", default="2"),
     *           @OA\Property(description="登录设备信息", property="mobile_mark", type="string", default="苹果13proMax1TB镶钻版"),
     *
     *           required={"username","password","verify_code","loing_type","mobile_mark"})
     *       )
     *     ),
     *   @OA\Response(
     *      response=200,
     *      description="The Member",
     *      @OA\JsonContent(type="object",
     *          @OA\Property(property="msg", type="string"),
     *          @OA\Property(property="code", type="integer", default="200"),
     *          @OA\Property(property="data", type="object",
     *          ),
     *      ),
     *   ),
     * )
     */
    public function index()
    {
        $client_type = 1;
        try {
            $loing_type = input('loing_type');
            $username = input('username');

            $validate_data = [
                'loing_type'  => input('loing_type'),
                'username'    => input('username'),
                'mobile_mark' => input('mobile_mark')
            ];

            validate(LoginValidate::class)->check($validate_data);

            if ($loing_type == 1) {
                $member_info = Db::name("member")->where("mobile", $username)->find();

                // 检测验证码
                if (!self::checkVerifySmsNoClean($username, $this->post['verify_code']))
                    throw new HttpExceptionHandle(HttpError::CODE_ERROR);

                if (empty($member_info))
                    throw new HttpExceptionHandle(HttpError::USER_PASSWORD_CODE_ERR);
            } else if ($loing_type == 2) {
                $member_info = Db::name("member")->where("mobile", $username)->find();

                if (empty($member_info))
                    throw new HttpExceptionHandle(HttpError::USER_PASSWORD_CODE_ERR);
            }

            if ($member_info['status'] == 2)
                throw new HttpExceptionHandle(HttpError::USER_FREEZE);

            if ($loing_type == 1) {
                // 手机号和验证码
                // 检测验证码
                if (!self::checkVerifySms($username, $this->post['verify_code']))
                    throw new HttpExceptionHandle(HttpError::SMS_VERIFY_CODE_ERR);

                $member_data = $this->member_model->login(3, $username, $this->post['verify_code'], 2, $this->module_name, $client_type);
            } else if ($loing_type == 2) {
                // 账号跟密码
                $member_data = $this->member_model->login(3, $username, $this->post['password'], 1, $this->module_name, $client_type);
            }

            if (isset($member_data['id']) && $member_data['id'] > 0) {
                $jwtauth = JwtAuth::getInstance();

                $token = $jwtauth->makeToken((int)$member_data['id'], (int)$member_data['appinit_type'])->getToken();
                // 重新查询
                $member_data = Member::getMemberWithInfo($member_data['id'], $member_data['appinit_type']);

                // 登录成功 添加登录记录
                $insert_data = [
                    'member_id'   => $member_data['id'],
                    'mobile_mark' => input('mobile_mark'),
                    'is_delete'   => 0,
                    'create_time' => date('Y-m-d H:i:s')
                ];
                Db::name('member_login_log')->insert($insert_data);

                // redis记录缓存
                saveRedisWeb($token, $member_data);

                return $this->jsonSyncSuccessData('登录成功', [
                    'token'       => $token,
                    'expiry_time' => $jwtauth->getExpireTime(),
                    'member'      => $member_data
                ]);
            } else {
                switch ($member_data) {
                    case -6:
                        throw new HttpExceptionHandle(HttpError::PASSWORD_UPDATE_ERROR);
                    case -5:
                        throw new HttpExceptionHandle(HttpError::SMS_VERIFY_CODE_ERR);
                    case -4:
                        throw new HttpExceptionHandle(HttpError::USER_PASSWORD_CODE_ERR);
                    case -3:
                        throw new HttpExceptionHandle(HttpError::USER_INVALID_ERR);
                    case -2:
                        throw new HttpExceptionHandle(HttpError::USER_DISABLED_ERR);
                    case -1:
                        throw new HttpExceptionHandle(HttpError::USER_NOT_EXIST);
                    default:
                        throw new HttpExceptionHandle(HttpError::LOGIN_FIAL_ERR);
                }
            }
        } catch (ValidateException $e) {
            Log::record('【登录】' . $e->getMessage() . $e->getFile() . $e->getLine());
            Log::record('【登录】参数' . json_encode(input('post.')));
            return $this->jsonFailData($e->getMessage());
        } catch (HttpExceptionHandle $e) {
            Log::record('【登录】' . $e->getMessage() . $e->getFile() . $e->getLine());
            Log::record('【登录】参数' . json_encode(input('post.')));
            return $this->jsonFailData($e->getMessage());
        } catch (Exception $e) {
            // 回滚事务
            Db::rollback();

            Log::record('【登录】' . $e->getMessage() . $e->getFile() . $e->getLine());
            Log::record('【登录】参数' . json_encode(input('post.')));
            return $this->jsonFailData("登录失败");
        }
    }


    /**
     * @OA\Post(path="/v1/register",
     *   tags={"登录管理"},
     *   summary="注册",
     *   @OA\Parameter(name="token", in="header", description="token", @OA\Schema(type="string", default="123456")),
     *     @OA\RequestBody(
     *     @OA\MediaType(
     *       mediaType="multipart/form-data",
     *         @OA\Schema(
     *           @OA\Property(description="手机号", property="username", type="string", default="15210999641"),
     *           @OA\Property(description="验证码", property="verify_code", type="string", default=""),
     *           @OA\Property(description="密码", property="password", type="string", default="123456"),
     *           @OA\Property(description="邀请码", property="referee", type="string", default="16jlD1qLj"),
     *           required={"username","verify_code","password"})
     *       )
     *     ),
     *   @OA\Response(
     *      response=200,
     *      description="The Member",
     *      @OA\JsonContent(type="object",
     *          @OA\Property(property="msg", type="string"),
     *          @OA\Property(property="code", type="integer", default="200"),
     *          @OA\Property(property="data", type="object",
     *          ),
     *      ),
     *   ),
     * )
     */
    public function register(): Json
    {
        $client_type = 1;

        try {
            $username = input('username');

            $validate_data['password'] = $this->post['password'];
            validate(PasswordValidate::class)->check($validate_data);
            if (!(preg_match('/[a-z]/', $validate_data['password']) && preg_match('/[A-Z]/', $validate_data['password']) && preg_match('/[0-9]/', $validate_data['password']))) {
                throw new ErrorException("密码请包含数字与大小写字母");
            }

            $member_info = Db::name("member")->where("mobile", $username)->find();

            if (!empty($member_info)) throw new ErrorException("已注册,请在登录页登录");

            // 检测验证码
            if (!self::checkVerifySms($username, $this->post['verify_code'])) throw new ErrorException("验证码错误");

            /**
             * 会员注册
             */
            $member_option = [
                "appinit_type"    => $client_type,
                'member_group_id' => 1,
                'login_num'       => 1,
            ];

            $member_option['mobile'] = $username;

            // 如果有邀请人
            $referee = input('referee');
            if ($referee) {
                // 获取上级id串
                $referee_member_data = Member::where(['code' => $referee])
                    ->findOrEmpty()
                    ->toArray();
                if (empty($referee_member_data)) throw new ErrorException("推荐人不存在");
                $member_option["parent_id"] = $referee_member_data['id'];
                if ($referee_member_data['parent_ids']) {
                    $member_option['parent_ids'] = $referee_member_data['parent_ids'] . ",[" . $referee_member_data['id'] . "]";
                } else {
                    $member_option['parent_ids'] = "[" . $referee_member_data['id'] . "]";
                }

                $ids = str_replace('[', '', $member_option['parent_ids']);
                $ids = str_replace(']', '', $ids);
            }

            if (!empty($this->post['password'])) {
                $member_option['password'] = sha1($this->post['password']);
            }

            // 验证通过
            // 启动事务
            Db::startTrans();

            $poython_data = [];
            $request_result = curl_post_request_arr(Env::get('app.wallet_url') . "/wallet/createWalletAddress", $poython_data);

            if (!isset($request_result['code']) || $request_result['code'] != 200) throw new Exception("网络连接失败");

            Log::record("【创建钱包地址】接口返回：" . json_encode($request_result));

            // 请求地址
            $member_option['account_address'] = $request_result['data'];

            $member_result = $this->member_model->save($member_option);
            $member_result_id = $this->member_model->id;

            Db::name('member_extend')->insert([
                'real_name_status' => 0,
                'member_id'        => $member_result_id,
                'create_time'      => date("Y-m-d H:i:s")
            ]);
            if (!$member_result) throw new Exception("注册失败");

            if ($referee) {
                // 所有上级人数+1
                Db::name('member')
                    ->where("id", $member_option['parent_id'])
                    ->inc("invite_count")
                    ->update();
                // 所有上级团队人数+1
                Db::name('member')
                    ->where('id', 'in', $ids)
                    ->inc("team_count")
                    ->update();
            }

            // 提交事务
            Db::commit();

            // 重新查询
            $member_info = Db::name("member")->where("id", $member_result_id)->find();

            $jwtauth = JwtAuth::getInstance();

            $token = $jwtauth->makeToken($this->member_model->id, $client_type)->getToken();

            // redis记录缓存
            saveRedisWeb($token, $member_info);

            return $this->jsonSyncSuccessData('注冊成功', [
                'token'       => $token,
                'expiry_time' => $jwtauth->getExpireTime(),
                'member'      => $member_info
            ]);

        } catch (ErrorException $e) {
            // 回滚事务
            Db::rollback();
            Log::record("【注册】" . $e->getMessage() . $e->getLine() . $e->getFile());

            return $this->jsonFailData($e->getMessage());
        } catch (ValidateException $e) {
            Log::record("【注册】" . $e->getMessage() . $e->getLine() . $e->getFile());

            return $this->jsonFailData($e->getMessage());
        } catch (Exception $e) {
            // 回滚事务
            Db::rollback();
            Log::record("【注册】" . $e->getMessage() . $e->getLine() . $e->getFile());

            return $this->jsonFailData(HttpError::SERVER_INTERNAL_ERROR[1]);
        }
    }

    /**
     * @OA\Post(path="/v1/setPassword",
     *   tags={"登录管理"},
     *   summary="重置密码",
     *   @OA\Parameter(name="token", in="header", description="token", @OA\Schema(type="string", default="123456")),
     *     @OA\RequestBody(
     *     @OA\MediaType(
     *       mediaType="multipart/form-data",
     *         @OA\Schema(
     *           @OA\Property(description="手机号", property="username", type="string", default="1"),
     *           @OA\Property(description="密码", property="password", type="string", default="123456"),
     *           @OA\Property(description="重复密码", property="repassword", type="string", default="123456"),
     *           @OA\Property(description="验证码", property="verify_code", type="string", default="1234"),
     *           required={"username","password","repassword","verify_code"})
     *       )
     *     ),
     *   @OA\Response(
     *      response=200,
     *      description="The Member",
     *      @OA\JsonContent(type="object",
     *          @OA\Property(property="msg", type="string"),
     *          @OA\Property(property="code", type="integer", default="200"),
     *          @OA\Property(property="data", type="object",
     *          ),
     *      ),
     *   ),
     * )
     */
    public function setPassword()
    {
        $username = input('username');

        $update['mobile'] = $username;
        $where['mobile'] = $username;

        $member_info = Db::name("member")->where($where)->find();// 判断比较两次密码是否一致

        if (array_key_exists("password", $this->post) || array_key_exists("repassword", $this->post)) {

            $validate_data['password'] = $this->post['password'];
            validate(PasswordValidate::class)->check($validate_data);
            if (!(preg_match('/[a-z]/', $validate_data['password']) && preg_match('/[A-Z]/', $validate_data['password']) && preg_match('/[0-9]/', $validate_data['password']))) {
                throw new ErrorException("密码请包含数字与大小写字母");
            }
            if ($this->post['password'] != $this->post['repassword']) {
                throw new ErrorException("两次密码不一致");
            }
            if (!self::checkVerifySms($username, $this->post['verify_code'])) {
                throw new ErrorException("验证码错误");
            }
            if (empty($member_info)) throw new Exception('不存在该用户');
            // 验证成功，修改密码

            $update['password'] = sha1($this->post['password']);
            if ($update['password'] == $member_info['password']) {
                throw new ErrorException("新旧密码不可一致，请重新输入");
            }
            Db::name("member")->where($where)->update($update);
            return $this->jsonSuccessData('操作成功');
        } else {
            throw new ErrorException("缺少必要参数");
        }

    }

}